package com.domus.dreamMenu.servidor.bancodados;

import java.awt.Toolkit;
import java.io.ByteArrayInputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.ImageIcon;

import com.domus.dreamMenu.tipos.Idioma;
import com.domus.dreamMenu.tipos.Ingrediente;
import com.domus.dreamMenu.tipos.Prato;
import com.domus.dreamMenu.tipos.PratoCampeao;
import com.domus.dreamMenu.tipos.Secao;
import com.domus.dreamMenu.tipos.excecoes.CodigoPratoInexistenteException;

public class ConexaoBancoDadosCardapio extends ConexaoBancoDados {

	public void inserirPrato(Prato novo){
		try {
			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("BEGIN;");
			comando.execute();

			comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO prato " +
			"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
			comando.setInt(1, novo.getCodigo());
			comando.setString(2, novo.getNome());
			comando.setFloat(3, novo.getPreco());
			if(novo.getFoto() != null)
				comando.setBinaryStream(4, new ByteArrayInputStream(novo.getFoto()), novo.getFoto().length);
			else
				comando.setBinaryStream(4, null, 0);
			comando.setInt(5, novo.getPrioridade());
			comando.setShort(6, (short) novo.getSecao());
			comando.setBoolean(7, novo.isHabilitado());
			comando.setFloat(8, 0);
			comando.setInt(9, 0);

			comando.executeUpdate();

			String [] descricoesCurtas = novo.getDescricoesCurtas();
			String [] descricoesCompletas = novo.getDescricoesCompletas();

			for (int i = 0; i <= Idioma.NUMERO_IDIOMAS-1; i++){				
				Idioma idioma = Idioma.getIdioma(i);

				if(descricoesCurtas[i] != null){
					comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO descricao_prato_idioma " +
					"VALUES (?, ?, ?, ?)");
					comando.setString(1, Idioma.getSiglaIdioma(idioma));
					comando.setString(2, descricoesCurtas[i]);
					comando.setString(3, "B");
					comando.setInt(4, novo.getCodigo());

					comando.executeUpdate();

				}

				if(descricoesCompletas[i] != null){
					comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO descricao_prato_idioma " +
					"VALUES (?, ?, ?, ?)");
					comando.setString(1, Idioma.getSiglaIdioma(idioma));
					comando.setString(2, descricoesCompletas[i]);
					comando.setString(3, "L");
					comando.setInt(4, novo.getCodigo());

					comando.executeUpdate();
				}							
			}

			Iterator<Ingrediente> ingredientes = novo.getIngredientes().iterator();
			Ingrediente atual;
			while(ingredientes.hasNext()){
				atual = ingredientes.next();
				comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO ingrediente " +
				"VALUES (NEXTVAL('ingrediente_id_seq'), ?)");
				comando.setInt(1, novo.getCodigo());

				comando.executeUpdate();

				String[] nomes = atual.getNomes();
				for(int i = 0; i <= Idioma.NUMERO_IDIOMAS-1; i++){
					Idioma idioma = Idioma.getIdioma(i);

					if(nomes[i] != null){
						comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO nome_ingrediente " +
						"VALUES (?, ?, CURRVAL('ingrediente_id_seq'))");
						comando.setString(1, Idioma.getSiglaIdioma(idioma));
						comando.setString(2, nomes[i]);

						comando.executeUpdate();
					}
				}
			}

			if(novo instanceof PratoCampeao){
				comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO prato_campeao " +
				"VALUES (?, ?)");
				comando.setInt(1, novo.getCodigo());
				comando.setString(2, ((PratoCampeao)novo).getTitulo());

				comando.executeUpdate();
			}

			comando = ConexaoBancoDados.conexao.prepareStatement("END;");
			comando.execute();

			ConexaoBancoDados.conexao.commit();

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void removerPrato(int codigo){
		try{
			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("DELETE FROM prato " +
			"WHERE codigo = ?");

			comando.setInt(1, codigo);

			comando.executeUpdate();

			ConexaoBancoDados.conexao.commit();

		} catch (SQLException e){
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void atualizarPrato (int codigo, Prato novo){

		try{
			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("BEGIN;");
			comando.execute();

			comando = ConexaoBancoDados.conexao.prepareStatement("UPDATE prato " + 
					"SET codigo = ?, nome = ?, preco = ?, foto = ?, prioridade = ?, habilitado = ?, " +
			"numero_secao = ? WHERE codigo = ?" );
			comando.setInt(1, novo.getCodigo());
			comando.setString(2, novo.getNome());
			comando.setFloat(3, novo.getPreco());
			if(novo.getFoto() != null)
				comando.setBinaryStream(4, new ByteArrayInputStream(novo.getFoto()), novo.getFoto().length);
			else
				comando.setBinaryStream(4, null, 0);
			comando.setInt(5, novo.getPrioridade());
			comando.setBoolean(6, novo.isHabilitado());
			comando.setShort(7, (short) novo.getSecao());
			comando.setInt(8,codigo);

			comando.executeUpdate();

			String [] descricoesCurtas = novo.getDescricoesCurtas();
			String [] descricoesCompletas = novo.getDescricoesCompletas();

			for (int i = 0; i <= Idioma.NUMERO_IDIOMAS-1; i++){				
				Idioma idioma = Idioma.getIdioma(i);

				if(descricoesCurtas[i] != null){
					comando = ConexaoBancoDados.conexao.prepareStatement("UPDATE descricao_prato_idioma " +
					"SET texto = ? WHERE codigo_prato = ? AND idioma = ? AND tipo = ?");
					comando.setString(1, descricoesCurtas[i]);
					comando.setInt(2, novo.getCodigo());
					comando.setString(3, Idioma.getSiglaIdioma(idioma));
					comando.setString(4, "B");

					comando.executeUpdate();

				}

				if(descricoesCompletas[i] != null){
					comando = ConexaoBancoDados.conexao.prepareStatement("UPDATE descricao_prato_idioma " +
					"SET texto = ? WHERE codigo_prato = ? AND idioma = ? AND tipo = ?");
					comando.setString(1, descricoesCompletas[i]);
					comando.setInt(2, novo.getCodigo());
					comando.setString(3, Idioma.getSiglaIdioma(idioma));
					comando.setString(4, "L");


					comando.executeUpdate();
				}							
			}

			comando = ConexaoBancoDados.conexao.prepareStatement("DELETE FROM ingrediente WHERE " +
			"codigo_prato = ?");
			comando.setInt(1, novo.getCodigo());

			Iterator<Ingrediente> ingredientes = novo.getIngredientes().iterator();
			Ingrediente atual;
			while(ingredientes.hasNext()){
				atual = ingredientes.next();
				comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO ingrediente " +
				"VALUES (NEXTVAL('ingrediente_id_seq'), ?)");
				comando.setInt(1, novo.getCodigo());

				comando.executeUpdate();

				String[] nomes = atual.getNomes();
				for(int i = 0; i <= Idioma.NUMERO_IDIOMAS-1; i++){
					Idioma idioma = Idioma.getIdioma(i);

					if(nomes[i] != null){
						comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO nome_ingrediente " +
						"VALUES (?, ?, CURRVAL('ingrediente_id_seq'))");
						comando.setString(1, Idioma.getSiglaIdioma(idioma));
						comando.setString(2, nomes[i]);
					}
				}
			}

			comando = ConexaoBancoDados.conexao.prepareStatement("END;");
			comando.execute();

			if(novo instanceof PratoCampeao){
				comando = ConexaoBancoDados.conexao.prepareStatement("UPDATE prato_campeao " +
				"SET titulo = ? WHERE codigo_prato = ?");
				comando.setString(1, ((PratoCampeao) novo).getTitulo());
				comando.setInt(2, novo.getCodigo());

				comando.executeUpdate();
			} else {
				comando = ConexaoBancoDados.conexao.prepareStatement("DELETE FROM prato_campeao " +
				"WHERE codigo_prato = ?");
				comando.setInt(1, novo.getCodigo());

				comando.executeUpdate();
			}

			ConexaoBancoDados.conexao.commit();		

		} catch (SQLException e){
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void inserirSecao(Secao novo){
		try {
			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("BEGIN;");
			comando.execute();

			comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO secao VALUES (?)");
			comando.setInt(1, novo.getNumero());

			String[] nomes = novo.getNomes();
			for(int i = 0; i <= Idioma.NUMERO_IDIOMAS-1; i++){
				Idioma idioma = Idioma.getIdioma(i);

				if(nomes[i] != null){
					comando = ConexaoBancoDados.conexao.prepareStatement("INSERT INTO nome_secao_idioma " +
					"VALUES (?, ?, ?)");
					comando.setString(1, Idioma.getSiglaIdioma(idioma));
					comando.setString(2, nomes[i]);
					comando.setInt(3, novo.getNumero());

					comando.executeUpdate();
				}
			}

			comando = ConexaoBancoDados.conexao.prepareStatement("END;");
			comando.execute();

			ConexaoBancoDados.conexao.commit();

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void removerSecao(int numero){
		try {
			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("DELETE FROM secao " + 
			"WHERE numero = ?");
			comando.setInt(1, numero);
			ConexaoBancoDados.conexao.commit();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void atualizarSecao(int numero, Secao novo){
		try {

			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("BEGIN;");
			comando.execute();

			comando = ConexaoBancoDados.conexao.prepareStatement("UPDATE secao SET " +
			"numero = ?) WHERE numero = ?");
			comando.setInt(1, novo.getNumero());
			comando.setInt(2, numero);

			String[] nomes = novo.getNomes();

			for(int i = 0; i <= Idioma.NUMERO_IDIOMAS-1; i++){				
				if(nomes[i] != null){
					comando = ConexaoBancoDados.conexao.prepareStatement("UPDATE nome_secao_idioma " +
					"SET texto = ? WHERE numero = ?");					
					comando.setString(1, nomes[i]);
					comando.setInt(2, novo.getNumero());

					comando.executeUpdate();
				}
			}

			comando = ConexaoBancoDados.conexao.prepareStatement("END;");
			comando.execute();

			ConexaoBancoDados.conexao.commit();

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public ArrayList<Secao> getCardapio(){		
		try {
			ArrayList<Secao> cardapio = new ArrayList<Secao>();

			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("SELECT numero " +
			"FROM secao ORDER BY numero");
			ResultSet resultSetSessoes = comando.executeQuery();

			int numeroSecao;
			ResultSet resultSetPratos;
			while(resultSetSessoes.next()){

				numeroSecao = resultSetSessoes.getInt(1);
				comando = ConexaoBancoDados.conexao.prepareStatement("SELECT p.codigo, p.nome, " +
						"p.preco, p.foto, p.prioridade, p.habilitado, p.nota, p.votos, pc.titulo " +
						"FROM prato p LEFT OUTER JOIN prato_campeao pc " +
				"ON (p.codigo = pc.codigo_prato) WHERE numero_secao = ?");
				comando.setInt(1, numeroSecao);
				resultSetPratos = comando.executeQuery();

				ArrayList<Prato> pratosSecao = new ArrayList<Prato>();

				ResultSet resultSetDescricoes;
				while(resultSetPratos.next()){
					int codigoPrato = resultSetPratos.getInt(1);
					String nome = resultSetPratos.getString(2);
					float preco = resultSetPratos.getFloat(3);
					byte [] foto = resultSetPratos.getBytes(4);
					int prioridade = resultSetPratos.getInt(5);
					boolean habilitado = resultSetPratos.getBoolean(6);
					float nota = resultSetPratos.getFloat(7);
					int votos = resultSetPratos.getInt(8);

					comando = ConexaoBancoDados.conexao.prepareStatement("SELECT idioma, texto, tipo " +
					"FROM descricao_prato_idioma WHERE codigo_prato = ?");
					comando.setInt(1, codigoPrato);
					resultSetDescricoes = comando.executeQuery();

					String[] descricoesCurtas = new String[Idioma.NUMERO_IDIOMAS];
					String[] descricoesCompletas = new String[Idioma.NUMERO_IDIOMAS];

					while(resultSetDescricoes.next()){
						String idioma = resultSetDescricoes.getString(1);
						String texto = resultSetDescricoes.getString(2);
						String tipo = resultSetDescricoes.getString(3);

						int indiceIdioma = Idioma.getNumeroIdiomaPelaSigla(idioma);

						if(tipo.equals("B"))
							descricoesCurtas[indiceIdioma] = texto;
						else if(tipo.equals("L"))
							descricoesCompletas[indiceIdioma] = texto;
					}

					comando = ConexaoBancoDados.conexao.prepareStatement("SELECT id FROM ingrediente " +
					"WHERE codigo_prato = ?");
					comando.setInt(1, codigoPrato);
					ResultSet resultSetIngredientes = comando.executeQuery();

					ArrayList<Ingrediente> ingredientes = new ArrayList<Ingrediente>();
					while(resultSetIngredientes.next()){
						int ingredienteId = resultSetIngredientes.getInt(1); 

						comando = ConexaoBancoDados.conexao.prepareStatement("SELECT idioma, texto FROM " +
						"nome_ingrediente_idioma WHERE ingrediente_id = ?");
						comando.setInt(1, ingredienteId);
						ResultSet resultSetNomesIngrediente = comando.executeQuery();

						String[] nomesIngrediente = new String[Idioma.NUMERO_IDIOMAS];
						while(resultSetNomesIngrediente.next()){
							String idioma = resultSetNomesIngrediente.getString(1);
							String texto = resultSetNomesIngrediente.getString(2);

							int indiceIdioma = Idioma.getNumeroIdiomaPelaSigla(idioma);

							nomesIngrediente[indiceIdioma] = texto;
						}

						ingredientes.add(new Ingrediente(nomesIngrediente, true));
					}

					String titulo = resultSetPratos.getString(9);
					if(titulo == null){					
						pratosSecao.add(new Prato(nome, descricoesCurtas, descricoesCompletas,
								preco, foto, habilitado, prioridade, codigoPrato, numeroSecao,
								nota, votos, ingredientes));
					} else {
						pratosSecao.add(new PratoCampeao(nome, descricoesCurtas, descricoesCompletas,
								preco, foto, habilitado, prioridade, codigoPrato, numeroSecao,
								nota, votos, ingredientes, titulo));
					}
				}

				ResultSet resultSetNomesSecao;
				comando = ConexaoBancoDados.conexao.prepareStatement("SELECT idioma, texto FROM " +
				"nome_secao_idioma WHERE numero_secao = ?");
				comando.setInt(1, numeroSecao);				
				resultSetNomesSecao = comando.executeQuery();

				String[] nomesSecao = new String[5];
				while(resultSetNomesSecao.next()){
					String idioma = resultSetNomesSecao.getString(1);
					String texto = resultSetNomesSecao.getString(2);

					int indiceIdioma = Idioma.getNumeroIdiomaPelaSigla(idioma);
					nomesSecao[indiceIdioma] = texto;
				}

				cardapio.add(new Secao(nomesSecao, pratosSecao, numeroSecao, Integer.MAX_VALUE));
			}

			resultSetSessoes.close();

			return cardapio;

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	public void computarVoto(int codigo, float nota){
		try {			
			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("UPDATE prato " +
			"SET nota = ((nota*votos) + ?)/(votos+1), votos = votos+1 WHERE codigo = ?");

			comando.setFloat(1, nota);
			comando.setInt(2, codigo);

			comando.executeUpdate();

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public Prato consultaPratoCodigo(Integer codigo) throws CodigoPratoInexistenteException {
		try {
			PreparedStatement comando = ConexaoBancoDados.conexao.prepareStatement("SELECT p.numero_secao, " +
					"p.nome, p.preco, p.foto, p.prioridade, p.habilitado, p.nota, p.votos, pc.titulo " +
					"FROM prato p LEFT OUTER JOIN prato_campeao pc " +
			"ON (p.codigo = pc.codigo_prato) WHERE codigo = ?");
			comando.setInt(1, codigo);

			ResultSet resultSetPrato = comando.executeQuery();

			if(!resultSetPrato.next())
				throw new CodigoPratoInexistenteException();

			int secao = resultSetPrato.getInt(1);
			String nome = resultSetPrato.getString(2);
			float preco = resultSetPrato.getFloat(3);
			byte[] foto = resultSetPrato.getBytes(4);
			int prioridade = resultSetPrato.getInt(5);
			boolean habilitado = resultSetPrato.getBoolean(6);
			float nota = resultSetPrato.getFloat(7);
			int votos = resultSetPrato.getInt(8);
			String titulo = resultSetPrato.getString(9);

			comando = ConexaoBancoDados.conexao.prepareStatement("SELECT idioma, texto, tipo " +
			"FROM descricao_prato_idioma WHERE codigo_prato = ?");
			comando.setInt(1, codigo);

			ResultSet resultSetDescricoes = comando.executeQuery();

			String[] descricoesCurtas = new String[Idioma.NUMERO_IDIOMAS];
			String[] descricoesCompletas = new String[Idioma.NUMERO_IDIOMAS];

			while(resultSetDescricoes.next()){
				String idioma = resultSetDescricoes.getString(1);
				String texto = resultSetDescricoes.getString(2);
				String tipo = resultSetDescricoes.getString(3);

				int indiceIdioma = Idioma.getNumeroIdiomaPelaSigla(idioma);

				if(tipo.equals("B"))
					descricoesCurtas[indiceIdioma] = texto;
				else if(tipo.equals("L"))
					descricoesCompletas[indiceIdioma] = texto;
			}

			
			comando = ConexaoBancoDados.conexao.prepareStatement("SELECT id FROM ingrediente " +
			"WHERE codigo_prato = ?");
			comando.setInt(1, codigo);
			
			ResultSet resultSetIngredientes = comando.executeQuery();
			ArrayList<Ingrediente> ingredientes = new ArrayList<Ingrediente>();
			
			while(resultSetIngredientes.next()){
				int ingredienteId = resultSetIngredientes.getInt(1); 

				comando = ConexaoBancoDados.conexao.prepareStatement("SELECT idioma, texto FROM " +
				"nome_ingrediente_idioma WHERE ingrediente_id = ?");
				comando.setInt(1, ingredienteId);
				ResultSet resultSetNomesIngrediente = comando.executeQuery();

				String[] nomesIngrediente = new String[Idioma.NUMERO_IDIOMAS];
				while(resultSetNomesIngrediente.next()){
					String idioma = resultSetNomesIngrediente.getString(1);
					String texto = resultSetNomesIngrediente.getString(2);

					int indiceIdioma = Idioma.getNumeroIdiomaPelaSigla(idioma);

					nomesIngrediente[indiceIdioma] = texto;
				}

				ingredientes.add(new Ingrediente(nomesIngrediente, true));
			}
			
			if(titulo == null)
				return new Prato(nome, descricoesCurtas, descricoesCompletas, preco, foto, habilitado,
					prioridade, codigo, secao, nota, votos, ingredientes);
			else
				return new PratoCampeao(nome, descricoesCurtas, descricoesCompletas, preco, foto,
					habilitado, prioridade, codigo, secao, nota, votos, ingredientes, titulo);
			
				

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
}
